#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <string.h>

/*
 * getopt_long是getopt的泛集, getopt是getopt_long的一个子集，
 * getopt支持的所有特性，getopt_long都支持，包括错误打印、argv元素顺序调整等;
 */


#if 0
#include <unistd.h>
extern char *optarg;    // 选项的参数指针
extern int optind,      // 下一次调用getopt的时，从optind存储的位置处重新开始检查选项。 
extern int opterr,      // 当opterr=0时，getopt不向stderr输出错误信息。
extern int optopt;      // 当命令行选项字符不包括在optstring中或者选项缺少必要的参数时，该选项存储在optopt 中，getopt返回'？’、

调用一次，返回一个选项。 

在命令行选项参数再也检查不到optstring中包含的选项时，返回－1，同时optind储存第一个不包含选项的命令行参数。


int getopt_long(int argc, char * const argv[],
      const char *optstring,
      const struct option *longopts, int *longindex);      

extern char *optarg;  
extern int optind, opterr, optopt;  

  longopts：长选项结构体
  longindex：不为NULL，则指向get_long获得的长选项longopts的下标
  其它：与getopt函数类似。

longopts 结构体

struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};

  const char *name：选项名，前面没有短横线;
  int has_arg：
        no_argument，值为0，选项没有参数
        required_argument，值为1，选项需要参数
        optional_argument，值为2，选项参数是可选的
  int *flag：
        如果该指针为NULL，那么getopt_long返回val字段的值；
        如果该指针不为NULL，那么会使得它所指向的结构填入val字段的值，同时getopt_long返回0
  int val：
        如果flag是NULL，那么val通常是个字符常量，如果短选项和长选项一致，那么该字符就应该与optstring中出现的这个选项的参数相同；

getopt_long_only与上述getopt_long不同之处：前者不管是"-"还是"--"都视为长选项，如果找不到的话，才去短选项哪里查找
#endif

#if 0
编写一个小程序，该程序可以接受以下选项，并完成相应的功能。

    --add或-a选项，将该选项后的两个参数相加，并输出结果；
    --square或-s选项，求该选项后的参数的平方，并输出结果；
    --list或-l选项，直接输出该选项后带的参数；
    能识别出错误选项，并给出提示信息；
#endif


int intchar(char * s)
{
	int i=0,sum=0;	
	while (s[i]){
		sum = 10 * sum + s[i] - '0';
		i++;
	}
	return sum;
}

int main(int argc, char *argv[])
{
	int opt;
	struct option longopts[] = {{"add", 1, NULL, 'a'},
								{"square", 1, NULL, 's'},
								{"list", 1, NULL, 'l'},
								{0,0,0,0}
								};

	int n,m,sum;

	printf("argc=%d\n", argc);
	while((opt = getopt_long(argc,argv,":a:s:l:",longopts,NULL))!=-1) {
		printf("optind=%d\n", optind);
		switch(opt) {
			case 'a':
				n = intchar(optarg);
				m = intchar(argv[optind]);
				printf("option: a, %d+%d=%d\n",n,m,n+m);
				break;
			case 's':
				sum = intchar(optarg);
				printf("option: s, %d*%d=%d\n",sum,sum,sum*sum);
				break;
			case 'l':
				printf("file is:%s\n", optarg);
				break;
			case ':':
           			printf("option needs a value\n");
				break;
			case '?':
			      printf("unknown option: %c\n", optopt);
			      break;
		}
    }

	exit(0);
}

